/**
 * 
 */
package org.swing.table.util;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.PatternSyntaxException;

import javax.naming.ldap.SortKey;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultRowSorter;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.RowFilter;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

import org.swing.table.model.DynamicTableModel;

/**
 * @author lqnhu
 *
 */
public class TableUtils {
	public static AbstractTableModel getDynamicModel(
			ArrayList<String> nombreColumnas) {
		DynamicTableModel temp = new DynamicTableModel(nombreColumnas);
		return temp;
	}

	public static void insertComponentInColumn(JTable jTable, int col,
			JComponent jComponent) {
		TableColumn sportColumn = jTable.getColumnModel().getColumn(col);
		if (jComponent instanceof JComboBox) {
			sportColumn.setCellEditor(new DefaultCellEditor(
					(JComboBox) jComponent));
		} else if (jComponent instanceof JCheckBox) {
			sportColumn.setCellEditor(new DefaultCellEditor(
					(JCheckBox) jComponent));
		} else if (jComponent instanceof JTextField) {
			sportColumn.setCellEditor(new DefaultCellEditor(
					(JTextField) jComponent));
		}
	}

	public static void addEmptyRow(JTable jTable) {
		DynamicTableModel dynamicModel = (DynamicTableModel) jTable.getModel();
		ArrayList<Object> newRow = new ArrayList<Object>();
		// fill with empty data this row
		for (int i = 0; i < dynamicModel.getColumnCount(); i++) {
			newRow.add("");
		}
		// add this row to model
		dynamicModel.getRows().add(newRow);
		// notify this change
		dynamicModel.fireTableRowsInserted(dynamicModel.getRows().size(),
				dynamicModel.getRows().size());
	}

	public static void addDataRow(JTable jTable, Collection<?> dataRow)
			throws Exception {
		DynamicTableModel dynamicModel = (DynamicTableModel) jTable.getModel();
		ArrayList<Object> newRow = new ArrayList<Object>();
		if (dataRow.size() != dynamicModel.getColumnCount()) {
			throw new Exception(
					String.format(
							"The number of columns of data do not match the model. Model[%d] ; Data Row[%d]",
							dynamicModel.getColumnCount(), dataRow.size()));
		}
		Iterator<?> it = dataRow.iterator();
		while (it.hasNext()) {
			newRow.add(it.next());
		}
		// add this row to model
		dynamicModel.getRows().add(newRow);
		// notify this change
		dynamicModel.fireTableRowsInserted(dynamicModel.getRows().size(),
				dynamicModel.getRows().size());
	}

	public static void removeRowJtableDinamic(JTable jTable) {
		// eliminar
		DynamicTableModel dinamicModel = (DynamicTableModel) jTable.getModel();
		int fila = jTable.getSelectedRow();// Obtengo numero de fila
											// seleccionada
		if (fila != -1) // Si hay fila seleccionada
		{
			if (jTable.isEditing()) {
				jTable.getCellEditor().cancelCellEditing();
			}
			dinamicModel.getRows().remove(fila);
			dinamicModel.fireTableRowsDeleted(fila, fila);
		} else {
		}
	}

	public static void clearJTable(JTable jTable) {
		DynamicTableModel dinamicModel = (DynamicTableModel) jTable.getModel();
		// int a = dinamicModel.getRowCount() - 1;
		// for (int i = a; i >= 0; i--) {
		// dinamicModel.getRows().remove(i);
		// }
		dinamicModel.clean();
		dinamicModel.fireTableDataChanged();
	}

	public static boolean containStringInColumn(JTable jTable, int col,
			String valueBuscado) {
		int num_rows = jTable.getRowCount();
		boolean resp = false;
		// iteramos la tabla
		for (int r = 0; r < num_rows; r++) {
			String valueTabla = "" + jTable.getValueAt(r, col);
			if (valueTabla.equalsIgnoreCase(valueBuscado)) {
				resp = true;
				break;
			}
		}
		return resp;
	}

	public static void pack(JTable table, boolean packColumns,
			boolean packRows, int padding) {
		final Enumeration<TableColumn> cols = table.getColumnModel()
				.getColumns();
		int[] rowHeights = new int[table.getRowCount()];
		while (cols.hasMoreElements()) {
			TableColumn tc = cols.nextElement();
			final int colIndex = tc.getModelIndex(); // not sure about this
			int width = 0;
			if (packColumns) {
				// Get width of column header
				TableCellRenderer renderer = tc.getHeaderRenderer();
				if (renderer == null) {
					final JTableHeader header = table.getTableHeader();
					if (header != null) {
						renderer = header.getDefaultRenderer();
					}
				}
				if (renderer != null) {
					Component comp = renderer.getTableCellRendererComponent(
							table, tc.getHeaderValue(), false, false, 0, 0);
					width = comp.getPreferredSize().width;
				}
			}
			// Check data
			for (int row = 0; row < table.getRowCount(); row++) {
				TableCellRenderer renderer = table.getCellRenderer(row,
						colIndex);
				Component comp = renderer.getTableCellRendererComponent(table,
						table.getValueAt(row, colIndex), false, false, row,
						colIndex);
				final Dimension prefSize = comp.getPreferredSize();
				if (packRows) {
					rowHeights[row] = Math
							.max(rowHeights[row], prefSize.height);
				}
				if (packColumns) {
					width = Math.max(width, prefSize.width);
				}
			}
			if (packColumns) {
				tc.setPreferredWidth(width);
			}
		}
		if (packRows) {
			for (int row = 0; row < rowHeights.length; row++) {
				table.setRowHeight(row, rowHeights[row] + (2 * padding));
			}
		}
	}

	public static void refreshTableRowHeight(JTable table) {
		table.setVisible(false);
		int lineHeight = table.getFontMetrics(table.getFont()).getHeight();
		for (int rowIndex = 0; rowIndex < table.getRowCount(); rowIndex++) {
			int maxRowInRowCount = 1;
			for (int columnIndex = 0; columnIndex < table.getColumnCount(); columnIndex++) {
				Object value = table.getValueAt(rowIndex, columnIndex);
				int rowInRowCount = 1;
				if (value instanceof String[]) {
					rowInRowCount = ((String[]) value).length;
				}
				maxRowInRowCount = Math.max(maxRowInRowCount, rowInRowCount);
			}
			table.setRowHeight(rowIndex, lineHeight * maxRowInRowCount + 1);
		}
		table.setVisible(true);
	}

	public static void addRow(JTable table, Object... data) {
		((DefaultTableModel) table.getModel()).addRow(data);
	}

	public static void insertRow(final JTable table, final int index,
			Object... data) {
		((DefaultTableModel) table.getModel()).insertRow(index, data);
	}

	public static void removeAllRows(JTable table) {
		DefaultTableModel model = (DefaultTableModel) table.getModel();
		for (int i = table.getRowCount() - 1; i > -1; i--) {
			model.removeRow(i);
		}
	}

	public static void removeRows(int[] selectedRows, final JTable successTable) {
		DefaultTableModel model = (DefaultTableModel) successTable.getModel();
		for (int i = selectedRows.length - 1; i > -1; i--) {
			model.removeRow(selectedRows[i]);
		}
	}

	public static void setColumnWidths(JTable tbl, Integer... widths) {
		TableColumnModel columnModel = tbl.getColumnModel();
		for (int i = 0; i < widths.length; i++) {
			if (widths[i] > -1) {
				columnModel.getColumn(i).setPreferredWidth(widths[i]);
			}
		}
	}

	public static void setColumnMaxWidths(JTable tbl, Integer... widths) {
		TableColumnModel columnModel = tbl.getColumnModel();
		for (int i = 0; i < widths.length; i++) {
			if (widths[i] > -1) {
				columnModel.getColumn(i).setMaxWidth(widths[i]);
			}
		}
	}

	public static void makeTableColumnWidthFit(JTable jTable, int col,
			int margin, boolean locking) {
		// strategy - get max width for cells in column and
		// make that the preferred width
		TableColumnModel columnModel = jTable.getColumnModel();
		int maxwidth = 0;

		for (int row = 0; row < jTable.getRowCount(); row++) {
			TableCellRenderer rend = jTable.getCellRenderer(row, col);
			Object value = jTable.getValueAt(row, col);
			Component comp = rend.getTableCellRendererComponent(jTable, value,
					false, false, row, col);

			maxwidth = Math.max(comp.getPreferredSize().width + margin,
					maxwidth);
		} // for row

		TableColumn column = columnModel.getColumn(col);
		TableCellRenderer headerRenderer = column.getHeaderRenderer();
		if (headerRenderer == null) {
			headerRenderer = jTable.getTableHeader().getDefaultRenderer();
		}
		Object headerValue = column.getHeaderValue();
		Component headerComp = headerRenderer.getTableCellRendererComponent(
				jTable, headerValue, false, false, 0, col);

		maxwidth = Math.max(maxwidth, headerComp.getPreferredSize().width
				+ margin);
		column.setPreferredWidth(maxwidth);
		if (locking) {
			// User will not able to adjust the width manually.
			column.setMinWidth(maxwidth);
			column.setMaxWidth(maxwidth);
		}
	}

	/**
	 * Scroll to visible.
	 * 
	 * @param table
	 *            the table
	 * @param rowIndex
	 *            the row index
	 * @param vColIndex
	 *            the v col index
	 */
	public static void scrollToVisible(JTable table, int rowIndex, int vColIndex) {
		if (!(table.getParent() instanceof JViewport)) {
			return;
		}

		JViewport viewport = (JViewport) table.getParent();

		// This rectangle is relative to the table where the
		// northwest corner of cell (0,0) is always (0,0).
		Rectangle rect = table.getCellRect(rowIndex, vColIndex, true);

		// The location of the viewport relative to the table
		Point pt = viewport.getViewPosition();

		// Translate the cell location so that it is relative
		// to the view, assuming the northwest corner of the
		// view is (0,0)
		rect.setLocation(rect.x - pt.x, rect.y - pt.y);

		// Scroll the area into view
		viewport.scrollRectToVisible(rect);
	}


	public static void packColumns(JTable table, int margin) {
		for (int c = 0; c < table.getColumnCount(); c++) {
			packColumn(table, c, 2);
		}
	}

	// Sets the preferred width of the visible column specified by vColIndex.
	// The column
	// will be just wide enough to show the column head and the widest cell in
	// the column.
	// margin pixels are added to the left and right
	// (resulting in an additional width of 2*margin pixels).
	public static void packColumn(JTable table, int vColIndex, int margin) {
		TableModel model = table.getModel();
		DefaultTableColumnModel colModel = (DefaultTableColumnModel) table
				.getColumnModel();
		TableColumn col = colModel.getColumn(vColIndex);
		int width = 0;
		// Get width of column header
		TableCellRenderer renderer = col.getHeaderRenderer();
		if (renderer == null) {
			renderer = table.getTableHeader().getDefaultRenderer();
		}
		Component comp = renderer.getTableCellRendererComponent(table,
				col.getHeaderValue(), false, false, 0, 0);
		width = comp.getPreferredSize().width;
		// Get maximum width of column data
		for (int r = 0; r < table.getRowCount(); r++) {
			renderer = table.getCellRenderer(r, vColIndex);
			comp = renderer.getTableCellRendererComponent(table,
					table.getValueAt(r, vColIndex), false, false, r, vColIndex);
			width = Math.max(width, comp.getPreferredSize().width);
		}
		// Add margin
		width += 2 * margin;
		// Set the width
		col.setPreferredWidth(width);
	}

	public static void setTableAlignmentValue(JTable table, int index) {
		DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
		renderer.setHorizontalAlignment(JLabel.CENTER);
		table.getColumnModel().getColumn(index).setCellRenderer(renderer);
	}



	// filer table, ignore case (case insensitive)
	public static void filterTable(JTable table, String text) {
		TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
				table.getModel());
		table.setRowSorter(sorter);
		if (text.equalsIgnoreCase(" ")) {
			sorter.setRowFilter(null);
		} else {
			try {
				sorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
			} catch (PatternSyntaxException e) {
			}
		}
	}

	public static void filterTable(final JTable table,
			final ArrayList<String> aList) {
		TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
				table.getModel());
		table.setRowSorter(sorter);
		sorter.setRowFilter(new RowFilter<TableModel, Object>() {
			public boolean include(Entry entry) {
				String row = String.valueOf(entry.getValue(0));
				if (aList.contains(row))
					return true;
				else
					return false;
			}
		});
	}

	public static Object[][] getTableData(JTable table) {
		TableModel dtm = (DefaultTableModel) table.getModel();
		int nRow = dtm.getRowCount(), nCol = dtm.getColumnCount();
		Object[][] tableData = new Object[nRow][nCol];
		for (int i = 0; i < nRow; i++) {
			for (int j = 0; j < nCol; j++) {
				tableData[i][j] = dtm.getValueAt(i, j);
			}
		}
		return tableData;
	}

	/**
	 * Add new row to table
	 */
	public static void addRowToJTable(final JTable table, final Object[] data) {
		DefaultTableModel tableModel = (DefaultTableModel) table.getModel();
		tableModel.addRow(data);
	}

	public static boolean isDoubleClick(MouseEvent evt) {
		return evt.getClickCount() == 2;
	}

}
